#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>

#pragma warning(disable : 4996)

int main(int argc, char** argv)
{
	if (argc != 2)
	{
		fprintf(stderr, "命令行参数错误\n");
		exit(3);
	}

	FILE* fp = fopen(argv[1], "rb");
	if (fp == NULL)
	{
		perror("无法打开文件");
		exit(1);
	}

	// 读文件头
	IMAGE_FILE_HEADER coffHeader;
	fread(&coffHeader, sizeof(coffHeader), 1, fp);
	time_t fileCreateTime = coffHeader.TimeDateStamp;

	printf("机器类型：0X%X\n", coffHeader.Machine);
	printf("段数量：0X%X\n", coffHeader.NumberOfSections);
	printf("符号数量：0X%X\n", coffHeader.NumberOfSymbols);
	printf("可选文件头大小：0X%X\n", coffHeader.SizeOfOptionalHeader);
	printf("符号表偏移地址：0X%X\n", coffHeader.PointerToSymbolTable);
	printf("文件属性：0X%X\n", coffHeader.Characteristics);
	printf("文件创建时间：%s\n", ctime(&fileCreateTime));
	puts("");

	// 读字符串表
	fseek(fp, coffHeader.PointerToSymbolTable + coffHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL), SEEK_SET);
	unsigned stringTableLen;
	fread(&stringTableLen, 4, 1, fp);
	stringTableLen -= 4;
	char* stringTable = NULL;
	if (stringTableLen != 0)
	{
		stringTable = (char*)malloc(sizeof(char) * stringTableLen);
		if (stringTable == NULL)
		{
			perror("无法分配内存");
			fclose(fp);
			exit(2);
		}
		fread(stringTable, 1, stringTableLen, fp);
	}

	// 读符号表
	IMAGE_SYMBOL* symbolTable = (IMAGE_SYMBOL*)malloc(sizeof(IMAGE_SYMBOL) * coffHeader.NumberOfSymbols);
	if (symbolTable == NULL)
	{
		perror("无法分配内存");
		fclose(fp);
		exit(2);
	}
	fseek(fp, coffHeader.PointerToSymbolTable, SEEK_SET);
	fread(symbolTable, sizeof(IMAGE_SYMBOL), coffHeader.NumberOfSymbols, fp);
	for (unsigned long long i = 0; i < coffHeader.NumberOfSymbols; i++)
	{
		if (symbolTable[i].N.Name.Short != 0)
		{
			symbolTable[i].N.ShortName[8] = 0;
			printf("符号名：%s\n", symbolTable[i].N.ShortName);
		}
		else
		{
			printf("符号名：%s\n", stringTable + symbolTable[i].N.Name.Long - 4);
		}
		printf("可重定位地址：0X%X\n", symbolTable[i].Value);
		printf("段表索引：0X%X\n", symbolTable[i].SectionNumber);
		printf("符号类型：0X%X\n", symbolTable[i].Type);
		printf("存储类别: 0X%X\n", symbolTable[i].StorageClass);
		printf("辅助符号数量: 0X%X\n", symbolTable[i].NumberOfAuxSymbols);
		puts("");
	}
	puts("");

	// 读段表
	fseek(fp, coffHeader.SizeOfOptionalHeader + sizeof(coffHeader), SEEK_SET);
	IMAGE_SECTION_HEADER* sectionTable = (IMAGE_SECTION_HEADER*)malloc(sizeof(IMAGE_SECTION_HEADER) * coffHeader.NumberOfSections);
	if (sectionTable == NULL)
	{
		perror("无法分配内存");
		fclose(fp);
		free(symbolTable);
		exit(2);
	}
	fread(sectionTable, sizeof(IMAGE_SECTION_HEADER), coffHeader.NumberOfSections, fp);
	for (int i = 0; i < coffHeader.NumberOfSections; i++)
	{
		printf("段名：%s\n", sectionTable[i].Name);
		printf("加载后占用内存：0X%X\n", sectionTable[i].Misc.VirtualSize);
		printf("段加载后地址：0X%X\n", sectionTable[i].VirtualAddress);
		printf("段实际大小：0X%X\n", sectionTable[i].SizeOfRawData);
		printf("段文件中偏移地址：0X%X\n", sectionTable[i].PointerToRawData);
		if (sectionTable[i].NumberOfRelocations)
		{
			printf("段重定位项偏移地址：0X%X\n", sectionTable[i].PointerToRelocations);
			printf("段重定位项数量：0X%X\n", sectionTable[i].NumberOfRelocations);
			// 读可重定位表
			IMAGE_RELOCATION* relocationTable = (IMAGE_RELOCATION*)malloc(sizeof(IMAGE_RELOCATION) * sectionTable[i].NumberOfRelocations);
			if (relocationTable == NULL)
			{
				perror("无法分配内存");
				fclose(fp);
				free(symbolTable);
				free(sectionTable);
				exit(2);
			}
			fseek(fp, sectionTable[i].PointerToRelocations, SEEK_SET);
			fread(relocationTable, sizeof(IMAGE_RELOCATION), sectionTable[i].NumberOfRelocations, fp);
			for (int j = 0; j < sectionTable[i].NumberOfRelocations; j++)
			{
				if (relocationTable[j].Type == 6 || relocationTable[j].Type == 7 || relocationTable[j].Type == 0x14)
				{
					printf("重定位项段内偏移地址：0X%X\n", relocationTable[j].VirtualAddress);
					printf("符号表索引：0X%X\n", relocationTable[j].SymbolTableIndex);
					printf("重定位类型：0X%X\n", relocationTable[j].Type);
				}
			}
		}
		if (sectionTable[i].NumberOfLinenumbers)
		{
			printf("段行号项偏移地址：0X%X\n", sectionTable[i].PointerToLinenumbers);
			printf("段行号项数量：0X%X\n", sectionTable[i].NumberOfLinenumbers);
		}
		printf("段属性：0X%X\n", sectionTable[i].Characteristics);
		puts("");
	}
	free(sectionTable);
	free(symbolTable);
	fclose(fp);
	return 0;
}